iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0
Modern Web

整合 Google 服務的燃料——透過 Google Apps Script (GAS) 加速你的工作速度系列 第 8

D8 - 如何用 Google Apps Script 將 Google Calendar 上的事件與更新全部列出到 Google Sheet 上?

  • 分享至 

  • xImage
  •  

來到了第 8 天。但一樣先講結論,如果你很急著用,可以直接使用這份 Add-On: Calendar to Sheet。如果想要自己試試看,那可以持續閱讀。對於想知道怎麼做的人,讓我們開始吧!

先來個小測驗


答案會在今天的文章中!

今天的目標

我們已經介紹了如何用 GAS 達到 (Google Form ->) Google Sheet -> Google Calendar 的流程。但如果今天我是想要反過來將 Google Calendar 上面的事件列出到 Google Sheet 呢? Google Calendar 內建的匯出是弄成 ICS 檔案。有沒有更簡單的方式可以直接在 Google Sheet 上面看到?這就是我們今天的主題。

  1. 如何讀取 Google Calendar 上面的所有事件?
  2. 如何讀取 Google Calendar 的特定事件?
  3. 如何將這些事件寫入 Google Sheet?

那我們就開始吧!


Q1. 如何讀取 Google Calendar 上面的所有事件?

Step 1 開啟 Google Sheet,並串起 GAS

因為我們要用到 Google Sheet ,所以一樣用其作為開啟的管道。

一樣執行時會有「需要驗證」出現,讓我借用一下 D2 的影片。

Step 2 確認要抓的行事曆資料並將其 ID 記錄到 GAS 上

這邊我們沿用昨天的兩份行事曆,待會會主要抓 meeting_room_A,也就是灰色的部分。

備註:這邊只做了四個在同一天的 mock events,但基本上可以抓出全部的事件。

如果是自己做,可以在建玩行事曆後,在「設定」這邊取得日曆的 ID。

接著,將兩個 ID 輸入到 GAS 的 environment.gs 當中。

這邊都跟昨天差不多。

Step 3 用 Calendar.Events.list(cal_ID) 抓出所有的 Calendar Event!

先用方式一,但因為這個 API 是舊版本的服務(v3),所以要多做點操作。但因為會列出所有的 Events,所以還是先介紹它。首先開立個 Calendar Service,在右手邊的服務中取得。

搞定 v3 的 Calendar API 後,就可以直接用其服務了抓到所有的 Calendar 物件了!

其 Object 大致上長這樣,我們待會再來看怎麼將其寫入 Google Sheet 當中。

讀出來的 Events 會依照創造的時間點排列,個人是建議可以先全部抓下來後再用 Google Sheet 進行排序 Sort。但實際使用上,我們會想知道一段時間的內事件,要怎麼進行有時間的搜索?這就到我們的 Q2 讀取特定 Google Calendar 事件。

Q2. 如何讀取 Google Calendar 的特定事件?

前兩步 Step 1 / Step 2 都跟 Q1 一樣。

Step 3 用 getEvents() 來取得特定時間內的行事曆

很簡單,基本上就是用 getEvents(startTime, endTime) 來取得資料。要記得輸入的 Time 都要是 Date Object。這邊來示範一次怎麼抓。

function getCalendarEvents(){
  let cal = CalendarApp.getCalendarById(room_A_ID);
  var date = new Date();
  var firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
  var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
  var events = cal.getEvents(firstDay, lastDay);
  Logger.log(events);
  Logger.log(events.length);
}

實際跑起來的樣子——

好,那接下來要怎麼「讀事件」呢?這就會回到我們最開始的小測驗。答案如下圖...。

至於 for...in 不行,有一個可能是因為 Calendar Array 不是 enumerable(出處),但詳細仍需要細節的研究。而答案寫成程式碼會變成這樣——

function getCalendarEvents(){
  let cal = CalendarApp.getCalendarById(room_A_ID);
  var date = new Date();
  var firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
  var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
  var events = cal.getEvents(firstDay, lastDay);
  for(let event of events){
    Logger.log(event.getStartTime())
  }

  for (let i=0; i< events.length;i++){
    Logger.log(events[i].getEndTime())
  }
}

好,那實際讀起來長什麼樣子,在這邊我兩個方式都示範;用方式一讀開始時間,用方式二讀結束時間。

其他功能,則可以參考其他每一個 Object 還可以用的 Methods: Calendar Event。如果想搜尋特定名稱的事件,可以考慮加上 options 。另外對於「整日事件」,則有另外的抓法可以參考—— getEventsForDay(date, options)

個人使用心得,雖然 Q1 是使用比較舊版的 API,但實際上它在抓資料時比較不囉唆,不會要限定時間和全天或時段事件。

Q3. 如何將這些事件寫入 Google Sheet 中?

Step 1 / 2 / 3 在 Q1 / Q2 都已經陳述過,這邊就專注在讀出來的資料要怎麼寫入。

這邊的邏輯是要「取範圍」 -> 「輸入數值」,重點也會是這兩步驟的細節怎麼寫。

Step 4 取資料表的範圍並用 setValues() 輸入數值

這邊用一個假的資料來做示範,今天也主要先示範如何輸入「矩形、正方形範圍」的資料。假設我要在 A2:B4 這個範圍內輸入輸入一個矩形——

Index A B C
2 a b c
3 d e f

先來看看程式碼。

function writeDate(){
  let data = [['a','b','c'],['d','e','f']];
  let starting_row = 2;
  let starting_col = 1;
  let num_row = data.length;
  let num_col = data[0].length;
  let sheet = SpreadsheetApp.getActiveSheet();
  let range = sheet.getRange(starting_row, starting_col,num_row,num_col);
  range.setValues(data);
}

也來看看這段程式碼會跑出的結果。

再來我們來讀一下 Code。其中大部分跟讀資料差不多,因為都要先取得範圍,可以回去參考 D6。其中一個不同的是,會是從 Array in array 的結構中取得 numRows(要取多少列) 和 numColumns(要取多少行)。這標要清楚的是 Array 的基本架構,可以搭配 W3C: Array 一起閱讀。

另外一個與 D6 不同的是透過 setValuse(),在使用時主要是要注意「範圍」要先給出來。也就是我要先知道我要貼多少行與列,這邊就用 .length 的方式取得,然後我們再將 data 改成外部輸入的變數。最後寫資料的程式碼改成這樣。

function writeData(data){
  let starting_row = 2;
  let starting_col = 1;
  let num_row = data.length;
  let num_col = data[0].length;
  let sheet = SpreadsheetApp.getActiveSheet();
  let range = sheet.getRange(starting_row, 
                             starting_col, 
                             num_row, 
                             num_col);
  range.setValues(data);
}

Step 5 將 Q1/Q2 串到 Q3

我們來將前面兩題串到第三題,我們先分別將 Q1 和 Q2 的 Code 寫成 Array in array 的格式。像是 Q1 的長這樣——

function getCalendarEventList(){
  var options = {
    maxResults: 100
  };
  let events = Calendar.Events.list(room_A_ID, options);
  let writed_data =[];

  for (let item of events.items){
    writed_data.push([item.id,
                      item.summary,
                      item.start,
                      item.end]);
  };
  Logger.log(writed_data)
}

跑起來長這樣——

而 Q2 寫起來長這樣——

function getCalendarEvents(){
  let cal = CalendarApp.getCalendarById(room_A_ID);
  let date = new Date();
  let firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
  let lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
  let events = cal.getEvents(firstDay, lastDay);
  let writed_data = []
  for(let event of events){
    writed_data.push([event.getTitle(),
                      event.getId(),
                      event.getStartTime(),
                      event.getEndTime()])
  }
  Logger.log(writed_data)
}

跑起來長這樣——

Uploading file..._pbko2z8ui

那最後就只要把 Logger.log(writed_data) 換成 writeData(writed_data) 就可以寫入資料庫了。

最後跑起來長這樣——


Reference

Google Advanced Calendar Service
Google Developer: Record time and activities in Calendar and Sheets


好,那我們就完成了。今天的份量比較多,主要學了...

  1. Calendar.Events.list(cal_ID) 抓出所有的 Calendar Event
  2. getEvents() 來取得特定時間內的行事曆事件
  3. 取資料表的範圍並用 setValues() 輸入數值
  4. 並結合以上三者

字數也來到了七千多(但這次貼的程式碼比較多),總之,希望能有所幫助。今天比較值得一提的是, Read Google Calendar Events 並沒有特別提到 Quota 限制,雖然相信還是會有,所以大家使用上仍是要多加留意。好,那今天就是我們的 D8,明天 D9 會來講講怎麼列出 Google Drive 裡面所有檔案 ID 與設定複雜權限。如果還有問題,透過留言之外,也可以到 Facebook Group,想開很久這次鐵人賽才真的開起來哈哈哈,歡迎來當 Founding Member。如果不想錯過可以訂閱按讚小鈴鐺(?),也歡迎留言跟我說你還想知道什麼做法/主題。我們明天見。


上一篇
D7 - 如何用 Google Apps Script 將 Google 表單的回應即時同步在多個行事曆上?
下一篇
D9 - 如何用 Google Apps Script 自動化對 Google Drive 的操作?(一)列出所有檔案 ID 與相關資訊
系列文
整合 Google 服務的燃料——透過 Google Apps Script (GAS) 加速你的工作速度30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言